package work

import (
	"check/config"
	"check/utils"
	"strings"
	"sync"

	"go.uber.org/atomic"
)

type Work struct {
	wg      sync.WaitGroup
	success atomic.Int64
	fail    atomic.Int64
	quit    chan struct{}
	lock    sync.Mutex
}

var WorkObj = NewWork()

func NewWork() *Work {
	w := Work{
		wg:      sync.WaitGroup{},
		success: atomic.Int64{},
		fail:    atomic.Int64{},
		quit:    make(chan struct{}),
		lock:    sync.Mutex{},
	}
	return &w
}

func (w *Work) Run() {
	go utils.HandleInterrupts(w.Quit)
	go utils.HandleTimeOut(config.Cfg.Elapsed, w.Quit)
	for i := 0; i <= config.Cfg.GoNum; i++ {
		w.wg.Add(1)
		if config.Cfg.GET {
			go w.WorkGet()
		}
		if config.Cfg.POST {
			go w.WorkPost()
		}
	}
	w.wg.Wait()
	w.Show()
}

func (w *Work) Quit() {
	w.lock.Lock()
	defer w.lock.Unlock()

	select {
	case <-w.quit:
		return
	default:
		close(w.quit)
	}
}

func (w *Work) WorkGet() {
	defer w.wg.Done()
	for {
		select {
		case <-w.quit:
			return
		default:
			resp, err := utils.Get(config.Cfg.URL)
			if err != nil {
				w.fail.Add(1)
				config.Log.Error(err)
				continue
			}
			if strings.Contains(string(resp), config.Cfg.Tag) {
				w.success.Add(1)
			} else {
				w.fail.Add(1)
			}

		}
	}
}

func (w *Work) WorkPost() {
	defer w.wg.Done()
	for {
		select {
		case <-w.quit:
			return
		default:
			resp, err := utils.Post(config.Cfg.URL, []byte(config.Cfg.PostData))
			if err != nil {
				w.fail.Add(1)
				config.Log.Error(err)
				continue
			}
			if strings.Contains(string(resp), config.Cfg.Tag) {
				w.success.Add(1)
			} else {
				w.fail.Add(1)
			}

		}
	}
}

func (w *Work) Show() {
	total := w.fail.Load() + w.success.Load()
	if total == 0 {
		total = 1
	}
	config.Log.Printf("fail: %-5d  %7.3f%%", w.fail.Load(), float64(w.fail.Load())/float64(total)*100.0)
	config.Log.Printf("Succ: %-5d  %7.3f%%", w.success.Load(), float64(w.success.Load())/float64(total)*100.0)
	config.Log.Printf("Total: %d", w.fail.Load()+w.success.Load())
}
